﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web.Mvc;
using Savvy.TestExtensions;

namespace MVCHelperExtensions.Test
{
  /// <summary>
  ///This is a test class for URLHelperExtensionsTest and is intended
  ///to contain all URLHelperExtensionsTest Unit Tests
  ///</summary>
  [TestClass()]
  public class URLHelperExtensionsTest
  {
    #region Details Tests
    #region Tests for default identifying properties
    [TestMethod()]
    public void PathTo_should_return_valid_path_to_details_view_for_the_instance_given_a_model_insance_with_defaults_only_no_attributes()
    {
      var modelInstance = new TestModel() { ID = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModels/Details/1",
        urlHelper.PathTo(modelInstance)
        );
    }

    [TestMethod()]
    public void PathTo_should_return_valid_path_to_details_view_for_the_instance_given_model_instance_with_Id_property()
    {
      var modelInstance = new TestModelWithId() { Id = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWithIds/Details/1",
        urlHelper.PathTo(modelInstance)
        );
    }

    [TestMethod()]
    public void PathTo_should_return_valid_path_to_details_view_for_a_model_instance_with_id_property()
    {
      var modelInstance = new TestModelWithid() { id = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWithids/Details/1",
        urlHelper.PathTo(modelInstance)
        );
    }

    [TestMethod()]
    public void PathTo_should_return_valid_path_to_details_view_for_a_given_model_instance_with__ID_property()
    {
      var modelInstance = new TestModelWith_ID() { _ID = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWith_IDs/Details/1",
        urlHelper.PathTo(modelInstance)
        );
    }

    [TestMethod()]
    public void PathTo_should_return_valid_path_to_details_view_for_a_given_model_instance_with__Id_property()
    {
      var modelInstance = new TestModelWith_Id() { _Id = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWith_Ids/Details/1",
        urlHelper.PathTo(modelInstance)
        );
    }

    [TestMethod()]
    public void PathTo_should_return_valid_path_to_details_view_for_a_given_model_instance_with__id_property()
    {
      var modelInstance = new TestModelWith_id() { _id = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWith_ids/Details/1",
        urlHelper.PathTo(modelInstance)
        );
    }
    #endregion

    [TestMethod()]
    public void PathTo_should_return_valid_path_to_details_view_for_a_given_model_instance_where_the_AlternateID_property_is_decorated_with_UrlHelperIdentifier_attribute()
    {
      var modelInstance = new TestModelWithAlternateID() { AlternateID = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWithAlternateIDs/Details/1",
        urlHelper.PathTo(modelInstance)
        );
    }

    [TestMethod()]
    public void PathTo_should_throw_exception_if_model_has_no_identifying_property()
    {
      var modelInstance = new TestModelWithoutID();
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      AssertExtensions.AssertThrows(
        typeof(NonInferrableModelIdException),
        () => { urlHelper.PathTo(modelInstance); }
      );
    }

    [TestMethod()]
    public void PathTo_should_get_controller_name_from_class_attribute()
    {
      var modelInstance = new TestModelWithControllerName_OtherController() { ID = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/OtherController/Details/1",
        urlHelper.PathTo(modelInstance)
        );
    }

    [TestMethod()]
    public void PathTo_should_return_valid_path_when_passed_a_class_with_UrlHelperDetailsMethodName_attribute()
    {
      var modelInstance = new TestModelWithDetailsMethodName_OtherDetails() { ID = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWithDetailsMethodName_OtherDetails/OtherDetails/1",
        urlHelper.PathTo(modelInstance)
        );
    }

    [TestMethod()]
    public void PathTo_should_return_valid_path_with_route_values()
    {
      var modelInstance = new TestModel() { ID = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModels/Details/1?urlparam=test",
        urlHelper.PathTo(modelInstance, new { urlparam = "test" })
        );
    }
    
    #region Make sure PathToDetails is working tests
    [TestMethod()]
    public void PathToDetails_should_return_valid_link()
    {
      var modelInstance = new TestModel() { ID = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModels/Details/1",
        urlHelper.PathTo(modelInstance)
        );   
    }
    [TestMethod()]
    public void PathToDetails_should_return_valid_link_with_route_values()
    {
      var modelInstance = new TestModel() { ID = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModels/Details/1?urlparam=test",
        urlHelper.PathTo(modelInstance, new { urlparam = "test" })
        );
    }
    #endregion
    #endregion

    #region Index Tests

    [TestMethod()]
    public void PathToIndex_passed_a_class_type_should_return_link_to_index_method()
    {
      var modelInstance = new TestModel();
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModels/Index",
        urlHelper.PathToIndex(typeof(TestModel))
        );
    }

    [TestMethod()]
    public void PathToIndex_should_returns_a_valid_link_using_a_class_with_an_alternate_index_method_name()
    {
      var modelInstance = new TestModelWithIndexMethodName_OtherIndex();
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWithIndexMethodName_OtherIndices/OtherIndex",
        urlHelper.PathToIndex(typeof(TestModelWithIndexMethodName_OtherIndex))
        );
    }

    [TestMethod()]
    public void PathToIndex_should_return_valid_link_when_passed_route_value_for_alternate_controller_name_and_additional_url_param()
    {
      var modelInstance = new TestModel();
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModels/Index?urlparam=test",
        urlHelper.PathToIndex(
          typeof(TestModel),
          new { urlparam = "test" } // route values
        ));
    }

    [TestMethod()]
    public void GenericPathToIndex_should_return_valid_link_without_route_values_or_html_attributes()
    {
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWithIndexMethodName_OtherIndices/OtherIndex",
        urlHelper.PathToIndex<TestModelWithIndexMethodName_OtherIndex>()
        );
    }

    [TestMethod()]
    public void GenericPathToIndex_should_return_valid_link_with_route_values_but_no_html_attributes()
    {
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWithIndexMethodName_OtherIndices/OtherIndex?urlparam=test",
        urlHelper.PathToIndex<TestModelWithIndexMethodName_OtherIndex>(
          new { urlparam = "test" } // route values
        ));
    }
    #endregion

    #region Edit Tests
    [TestMethod()]
    public void PathToEdit_should_return_valid_Path_when_passed_a_model_instance_without_decoration_attributes()
    {
      var modelInstance = new TestModel() { ID = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModels/Edit/1",
        urlHelper.PathToEdit(modelInstance)
        );
    }

    [TestMethod()]
    public void PathToEdit_should_return_valid_Path_when_passed_a_model_instance_with_alternative_edit_action_name_attribute()
    {
      var modelInstance = new TestModelWithEditMethodName_OtherEdit() { ID = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWithEditMethodName_OtherEdits/OtherEdit/1",
        urlHelper.PathToEdit(modelInstance)
        );
    }

    [TestMethod()]
    public void PathToEdit_should_return_valid_Path_with_route_values()
    {
      var modelInstance = new TestModel() { ID = 1 };
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModels/Edit/1?urlparam=test",
        urlHelper.PathToEdit(modelInstance, new { urlparam = "test" }// route values
        ));
    }
    #endregion   
    
    #region New Tests
    [TestMethod()]
    public void PathToNew_passed_a_class_type_should_return_a_valid_Path()
    {
      var modelInstance = new TestModel();
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModels/Create",
        urlHelper.PathToNew(typeof(TestModel))
        );
    }

    [TestMethod()]
    public void PathToNew_should_returns_a_valid_Path_using_a_class_with_an_alternate_New_method_name()
    {
      var modelInstance = new TestModelWithNewMethodName_OtherNew();
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWithNewMethodName_OtherNews/OtherNew",
        urlHelper.PathToNew(typeof(TestModelWithNewMethodName_OtherNew))
        );
    }

    [TestMethod()]
    public void PathToNew_should_return_valid_Path_when_passed_route_value_for_alternate_controller_name_and_additional_url_param()
    {
      var modelInstance = new TestModel();
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModels/Create?urlparam=test",
        urlHelper.PathToNew(typeof(TestModel), new { urlparam = "test" }// route values
        ));
    }

    #region Make sure generic version (alias) of PathToNew works
    [TestMethod()]
    public void GenericPathToNew_should_return_valid_Path_without_route_values_or_html_attributes()
    {
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWithNewMethodName_OtherNews/OtherNew",
        urlHelper.PathToNew<TestModelWithNewMethodName_OtherNew>()
        );
    }

    [TestMethod()]
    public void GenericPathToNew_should_return_valid_Path_with_route_values_but_no_html_attributes()
    {
      UrlHelper urlHelper = TestHelpers.GetUrlHelperWithDefaultHttpContext();

      Assert.AreEqual(
        @"/TEST_APP_MODIFIER/app/TestModelWithNewMethodName_OtherNews/OtherNew?urlparam=test",
        urlHelper.PathToNew<TestModelWithNewMethodName_OtherNew>(new { urlparam = "test" }// route values
        ));
    }
    #endregion
    #endregion
  }
}
